

#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#include <wx/stdpaths.h>
#include <wx/process.h>
#include <wx/filename.h>
#include <wx/filesys.h>
#include <wx/fs_zip.h>
#include <wx/fs_mem.h>
#include <wx/xrc/xmlres.h>
#include <wx/dynlib.h>
#include <wx/dir.h>

#if defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h>
#include <mach-o/dyld.h>
#endif

#include "prep.h"
#include "xtra_res.h"
#include "configmanager.h"
#include "seditormanager.h"

#include "version.h"
#include "codesnippetsapp.h"
#include "codesnippetswindow.h"
#include "snippetsconfig.h"
#include "snippetsimages.h"
#include "GenericMessageBox.h"
#include "codesnippetsevent.h"
#include "FileImport.h"
#include "dragscroll.h"
#include "dragscrollevent.h"


#ifndef APP_PREFIX
#define APP_PREFIX ""
#endif

#ifndef __WXMAC__
wxString GetResourcesDir() { return wxEmptyString; };
#endif

#define MAPVK_VK_TO_VSC     0

IMPLEMENT_APP(CodeSnippetsApp);

int fileOpenRecentFilesSubMenu =        wxNewId();
int idFileOpenRecentFileClearHistory =  wxNewId();
int idFileOpenRecentFile =              wxNewId();

BEGIN_EVENT_TABLE(CodeSnippetsApp, wxApp)

END_EVENT_TABLE()

#ifdef __WXMAC__
#if wxCHECK_VERSION(3, 0, 0)
#include "wx/osx/core/cfstring.h"
#else
#include "wx/mac/corefoundation/cfstring.h"
#endif
#include "wx/intl.h"

#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFURL.h>




static wxString GetResourcesDir()

{
  CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
  CFURLRef absoluteURL = CFURLCopyAbsoluteURL(resourcesURL);
  CFRelease(resourcesURL);
  CFStringRef cfStrPath = CFURLCopyFileSystemPath(absoluteURL, kCFURLPOSIXPathStyle);
  CFRelease(absoluteURL);
  #if wxCHECK_VERSION(3, 0, 0)
  return wxCFStringRef(cfStrPath).AsString(wxLocale::GetSystemEncoding());
  #else
  return wxMacCFStringHolder(cfStrPath).AsString(wxLocale::GetSystemEncoding());
  #endif
}
#endif


bool CodeSnippetsApp::OnInit() {
  wxLog::EnableLogging(true);
  SetConfig(new CodeSnippetsConfig);
  GetConfig()->m_bIsPlugin = false;
  CodeSnippetsAppFrame* frame = new CodeSnippetsAppFrame(0L, _("CodeSnippets"));
  if(GetConfig()->m_sWindowHandle.IsEmpty())
    return false;
  if(frame->GetInitXRCResult() == false)
    return false;
  frame->Show();
  return true;
}

int CodeSnippetsApp::OnExit() {
  return 0;
}



#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif



enum wxbuildinfoformat {
  short_f, long_f
};

wxString wxbuildinfo(wxbuildinfoformat format) {
  wxString wxbuild(wxVERSION_STRING);
  if(format == long_f) {
    #if defined(__WXMSW__)
    wxbuild << _T("-Windows");
    #elif defined(__UNIX__)
    wxbuild << _T("-Linux");
    #endif
    #if wxUSE_UNICODE
    wxbuild << _T("-Unicode build");
    #else
    wxbuild << _T("-ANSI build");
    #endif
  }
  return wxbuild;
}

int idViewSnippets = wxNewId();

int idMenuFileOpen              = wxNewId();
int idMenuFileSave              = wxNewId();
int idMenuFileSaveAs            = wxNewId();
int idMenuFileBackup            = wxNewId();
int idMenuQuit                  = wxNewId();
int idMenuSettingsOptions       = wxNewId();

int idMenuAbout                 = wxNewId();
int idMenuTest                  = wxNewId();

BEGIN_EVENT_TABLE(CodeSnippetsAppFrame, wxFrame)
  EVT_MENU(idMenuFileOpen,        CodeSnippetsAppFrame::OnFileLoad)
  EVT_MENU(idMenuFileSave,        CodeSnippetsAppFrame::OnFileSave)
  EVT_MENU(idMenuFileSaveAs,      CodeSnippetsAppFrame::OnFileSaveAs)
  EVT_MENU(idMenuFileBackup,      CodeSnippetsAppFrame::OnFileBackup)
  EVT_MENU(idMenuAbout,           CodeSnippetsAppFrame::OnAbout)
  EVT_MENU(idMenuQuit,            CodeSnippetsAppFrame::OnQuit)
  EVT_MENU(idMenuSettingsOptions, CodeSnippetsAppFrame::OnSettings)

  EVT_TIMER(-1,                   CodeSnippetsAppFrame::OnTimerAlarm)

  EVT_ACTIVATE(CodeSnippetsAppFrame::OnActivate)
  EVT_CLOSE(CodeSnippetsAppFrame::OnClose)
  EVT_IDLE(CodeSnippetsAppFrame::OnIdle)

  EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9,      CodeSnippetsAppFrame::OnRecentFileReopen)
  EVT_MENU(idFileOpenRecentFileClearHistory,  CodeSnippetsAppFrame::OnRecentFileClearHistory)


#if defined(LOGGING)
  EVT_MENU(idMenuTest,        CodeSnippetsAppFrame::OnEventTest)
#endif
END_EVENT_TABLE()


CodeSnippetsAppFrame::CodeSnippetsAppFrame(wxFrame* frame, const wxString& title)

  : wxFrame(frame, -1, title)
  , m_Timer(this, 0) {
  frame = this;
  InitCodeSnippetsAppFrame(frame, title);
}
CodeSnippetsAppFrame::~CodeSnippetsAppFrame() {
}

void CodeSnippetsAppFrame::InitCodeSnippetsAppFrame(wxFrame *frame, const wxString& title) {
  GetConfig()->pMainFrame      = 0;
  GetConfig()->pSnippetsWindow = 0;
  GetConfig()->m_appIsShutdown = 0;
  GetConfig()->m_appIsDisabled = 0;
  m_bOnActivateBusy = 0;
  GetConfig()->SetKeepAlivePid(0);
  GetConfig()->SetAppParent(wxEmptyString);
  m_KeepAliveFileName = wxEmptyString;
  m_pFilesHistory = 0;
  AppVersion* pVersion = new AppVersion;
  GetConfig()->pMainFrame = this;
  GetConfig()->AppName = wxT("codesnippets");
  #if LOGGING
  wxWindow* m_pAppWin = this;
  wxLog::EnableLogging(true);
  m_pLog = new wxLogWindow(m_pAppWin, _T(" CodeSnippets Log"), true, false);
  wxLog::SetActiveTarget(m_pLog);
  m_pLog->Flush();
  m_pLog->GetFrame()->SetSize(20, 20, 600, 300);
  LOGIT(_T("CodeSnippets App Logging Started[%s]"), pVersion->GetVersion().c_str());
  #endif
  #if defined(LOGGING)
  LOGIT(wxT("AppName is[%s]"), GetConfig()->AppName.c_str());
  #endif
  if(wxTheApp->argc > 1)
    do {
      wxString keepAliveArg = wxTheApp->argv[1];
      if(not keepAliveArg.Contains(wxT("KeepAlivePid")))
        break;
      wxString keepAlivePid = keepAliveArg.AfterLast('=');
      long lKeepAlivePid = 0;
      keepAlivePid.ToLong(&lKeepAlivePid);
      GetConfig()->SetKeepAlivePid(lKeepAlivePid);
      #if defined(LOGGING)
      LOGIT(_T("App: KeepAlivePid is [%lu]"), GetConfig()->GetKeepAlivePid());
      #endif
    } while(false);
  if(wxTheApp->argc > 2)
    do {
      wxString appParentArg = wxTheApp->argv[2];
      if(not appParentArg.Contains(wxT("AppParent")))
        break;
      wxString appParent = appParentArg.AfterLast('=');
      GetConfig()->SetAppParent(appParent);
      #if defined(LOGGING)
      LOGIT(_T("App: AppParent is [%s]"), GetConfig()->GetAppParent().c_str());
      #endif
    } while(false);
  m_ConfigFolder = Normalize(wxStandardPaths::Get().GetUserDataDir());
  wxString m_ExecuteFolder = Normalize(FindAppPath(wxTheApp->argv[0], ::wxGetCwd(), wxEmptyString));
  #if defined(LOGGING)
  LOGIT(wxT("CfgFolder[%s]"), m_ConfigFolder.c_str());
  LOGIT(wxT("ExecFolder[%s]"), m_ExecuteFolder.c_str());
  #endif
  wxString iniFilenameStr;
  do {
    iniFilenameStr = m_ExecuteFolder + wxFILE_SEP_PATH + GetConfig()->AppName + _T(".ini");
    if(::wxFileExists(iniFilenameStr)) {
      m_ConfigFolder = m_ExecuteFolder;
      GetConfig()->SettingsSnippetsCfgPath = m_ExecuteFolder;
      break;
    }
    wxString defaultconfStr =  m_ExecuteFolder + wxFILE_SEP_PATH + _T("default.conf");
    if(::wxFileExists(defaultconfStr)) {
      m_ConfigFolder = m_ExecuteFolder;
      GetConfig()->SettingsCBConfigPath = m_ExecuteFolder;
      break;
    }
    iniFilenameStr = m_ConfigFolder + wxFILE_SEP_PATH + GetConfig()->AppName + _T(".ini");
    iniFilenameStr = iniFilenameStr.Lower();
    iniFilenameStr.Replace(wxT("codesnippets"), GetConfig()->GetAppParent(), false);
    if(GetConfig()->GetKeepAlivePid())
      if(::wxFileExists(iniFilenameStr))
        break;
    iniFilenameStr.Replace(GetConfig()->GetAppParent(), _T(".") + GetConfig()->GetAppParent());
    if(GetConfig()->GetKeepAlivePid())
      if(::wxFileExists(iniFilenameStr))
        break;
    iniFilenameStr = m_ConfigFolder + wxFILE_SEP_PATH + GetConfig()->AppName + _T(".ini");
  } while(0);
  #if defined(LOGGING)
  LOGIT(_T("using .ini at[%s]"), iniFilenameStr.c_str());
  #endif
  GetConfig()->SettingsSnippetsCfgPath = iniFilenameStr;
  wxString defaultconfStr =  m_ExecuteFolder + wxFILE_SEP_PATH + _T("default.conf");
  if(::wxFileExists(defaultconfStr))
    GetConfig()->SettingsCBConfigPath = m_ExecuteFolder;
  #if defined(LOGGING)
  LOGIT(_T("SettingsSnippetsCfgPath[%s]"), GetConfig()->SettingsSnippetsCfgPath.c_str());
  #endif
  GetConfig()->SettingsLoad();
  if(GetConfig()->GetSettingsWindowState() not_eq _T("External")) {
    GetConfig()->SetSettingsWindowState(_T("External"));
    GetConfig()->SettingsSaveString(wxT("WindowState"), _T("External"));
  }
  ImportCBResources();
  #if defined(__WXMSW__)
  const wxString name = wxString::Format(wxT("CodeSnippets-%s"), wxGetUserId().c_str());
  m_checker = new wxSingleInstanceChecker(name);
  if(m_checker->IsAnotherRunning())
    do {
      HWND pFirstInstance;
      #if defined(_WIN64) | defined(WIN64)
      size_t val;
      if(GetConfig()->m_sWindowHandle.ToULongLong(&val, 16))
      #else
      long unsigned int val;
      if(GetConfig()->m_sWindowHandle.ToULong(&val, 16))
      #endif
        pFirstInstance = (HWND)val;
      if(pFirstInstance && ::IsWindow(pFirstInstance)) {
        wxString msg = wxT("Another CodeSnippets is already running from this folder.\n");
        msg << _T("Starting multiple CodeSnippets could scramble this configuration file.\n");
        msg << _T("Run multiple CodeSnippets anyway?\n");
        int answer = GenericMessageBox(msg, _T("Multiple CodeSnippets"), wxYES_NO);
        if(answer == wxYES)
          break;
        GetConfig()->m_sWindowHandle = wxEmptyString;
        return ;
      }
    } while(0);
  #endif
  GetConfig()->m_sWindowHandle = wxString::Format(wxT("%p"), this->GetHandle());
  GetConfig()->SettingsSaveString(wxT("WindowHandle"), GetConfig()->m_sWindowHandle);
  if(not InitializeSDK()) {
    GetConfig()->m_sWindowHandle = wxEmptyString;
    return;
  }
  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("app"));
  GetConfig()->SettingsCBConfigPath = cfg->GetConfigFolder();
  defaultconfStr =  m_ExecuteFolder + wxFILE_SEP_PATH + _T("default.conf");
  if(::wxFileExists(defaultconfStr))
    GetConfig()->SettingsCBConfigPath = m_ExecuteFolder;
  wxMenuBar* mbar = new wxMenuBar();
  wxMenu* fileMenu = new wxMenu(_T(""));
  fileMenu->Append(idMenuFileOpen, _("&Load Index...\tCtrl-O"), _("Load Snippets"));
  fileMenu->Append(idMenuFileSave, _("&Save Index\tCtrl-S"), _("Save Snippets"));
  fileMenu->Append(idMenuFileSaveAs, _("Save Index &As..."), _("Save Snippets As..."));
  fileMenu->Append(idMenuFileBackup, _("Backup Index "), _("Backup Snippets Index"));
  wxMenu* fileOpenRecentFilesSubMenu = new wxMenu(wxT(""));
  fileOpenRecentFilesSubMenu->Append(idFileOpenRecentFileClearHistory, _("Clear History"), _("Clear Recent History"));
  fileMenu->Append(idFileOpenRecentFile, _("Recent History"), fileOpenRecentFilesSubMenu, _("Recent Files History"));
  fileMenu->Append(idMenuQuit, _("&Quit\tAlt-F4"), _("Quit the application"));
  mbar->Append(fileMenu, _("&File"));
  wxMenu* settingsMenu = new wxMenu(_T(""));
  settingsMenu->Append(idMenuSettingsOptions, _("Options..."), _("Configuration Options"));
  #if defined(LOGGING)
  settingsMenu->Append(idMenuTest, _("Test"), _("Testing"));
  #endif
  mbar->Append(settingsMenu, _("Settings"));
  wxMenu* helpMenu = new wxMenu(_T(""));
  helpMenu->Append(idMenuAbout, _("&About\tF1"), _("Show info about this application"));
  mbar->Append(helpMenu, _("&Help"));
  SetMenuBar(mbar);
  GetConfig()->m_pMenuBar = mbar;
  InitializeRecentFilesHistory();
  CreateStatusBar(1);
  versionStr = versionStr + wxT("CodeSnippets") + wxT(" ") + pVersion->GetVersion();
  SetStatusText(versionStr, 0);
  SetStatusText(wxbuildinfo(short_f), 1);
  GetConfig()->pSnipImages = new SnipImages();
  SetIcon(GetConfig()->GetSnipImages()->GetSnipListIcon(TREE_IMAGE_ALL_SNIPPETS));
  GetConfig()->pMainFrame = this;
  GetConfig()->pSnippetsWindow = new CodeSnippetsWindow(this);
  wxBoxSizer* m_pMainSizer = new wxBoxSizer(wxVERTICAL);
  m_pMainSizer->Add(GetSnippetsWindow(), 1, wxEXPAND);
  SetSizer(m_pMainSizer);
  Layout();
  if(GetConfig()->windowWidth < 20)
    GetConfig()->windowWidth = 100;
  if(GetConfig()->windowHeight < 40)
    GetConfig()->windowHeight = 200;
  SetSize(GetConfig()->windowXpos, GetConfig()->windowYpos,
          GetConfig()->windowWidth, GetConfig()->windowHeight);
  buildInfo = wxbuildinfo(long_f);
  wxString
  pgmVersionString = wxT("CodeSnippets v") + pVersion->GetVersion();
  buildInfo = wxT("\t") + pgmVersionString + wxT("\n") + wxT("\t") + buildInfo;
  buildInfo = buildInfo + wxT("\n\n\t") + wxT("Original Code by Arto Jonsson");
  buildInfo = buildInfo + wxT("\n\t") + wxT("Modified/Enhanced by Pecan Heber");
  if(wxTheApp->argc > 1)
    do {
      wxString keepAliveArg = wxTheApp->argv[1];
      if(not keepAliveArg.Contains(wxT("KeepAlivePid")))
        break;
      wxString keepAlivePid = keepAliveArg.AfterLast('=');
      long lKeepAlivePid = 0;
      keepAlivePid.ToLong(&lKeepAlivePid);
      GetConfig()->SetKeepAlivePid(lKeepAlivePid);
      #if defined(LOGGING)
      LOGIT(_T("App: KeepAlivePid is [%lu]"), GetConfig()->GetKeepAlivePid());
      #endif
      wxString tempDir = GetConfig()->GetTempDir();
      m_KeepAliveFileName = tempDir + wxT("/cbsnippetspid") + keepAlivePid + wxT(".plg");
      #if defined(LOGGING)
      LOGIT(_T("KeepAlive FileName[%s]"), m_KeepAliveFileName.GetData());
      #endif
      if(not ::wxFileExists(m_KeepAliveFileName)) {
        GenericMessageBox(wxString::Format(wxT("Error: Did not find KeepAlive File[%s]"), m_KeepAliveFileName.GetData()));
        m_KeepAliveFileName = wxEmptyString;
        break;
      }
      if(GetConfig()->GetKeepAlivePid()) {
        StartKeepAliveTimer(2);
        #if defined(LOGGING)
        LOGIT(_T("StartKeepAliveTimer for[%lu]"), GetConfig()->GetKeepAlivePid());
        #endif
      }
    } while(0);
  InitializeDragScroll();
  sDragScrollEvent dsevt(wxEVT_S_DRAGSCROLL_EVENT, idDragScrollAddWindow);
  dsevt.SetEventObject(GetConfig()->GetSnippetsTreeCtrl());
  dsevt.SetString(GetConfig()->GetSnippetsTreeCtrl()->GetName());
  GetConfig()->GetDragScrollEvtHandler()->AddPendingEvent(dsevt);
}

void CodeSnippetsAppFrame::InitializeDragScroll() {
  GetConfig()->SetDragScrollPlugin(0);
  GetConfig()->SetDragScrollPlugin(new cbDragScroll());
  cbDragScroll* pds = GetConfig()->GetDragScrollPlugin();
  pds->cbDragScroll::m_IsAttached = true;
  pds->OnAttach();
  PushEventHandler(pds);
  pds->SetEvtHandlerEnabled(true);
  CodeBlocksEvent evt;
  pds->OnAppStartupDone(evt);
}
wxString CodeSnippetsAppFrame::FindAppPath(const wxString& argv0, const wxString& cwd, const wxString& appVariableName) {
  wxString str;
  if(!appVariableName.IsEmpty()) {
    str = wxGetenv(appVariableName);
    if(!str.IsEmpty())
      return str;
  }
  #if defined(__WXMAC__) && !defined(__DARWIN__)
  return cwd;
  #endif
  wxString argv0Str = argv0;
  #if defined(__WXMSW__)
  do {
    if(argv0Str.Contains(wxT(".exe")))
      break;
    if(argv0Str.Contains(wxT(".bat")))
      break;
    if(argv0Str.Contains(wxT(".cmd")))
      break;
    argv0Str.Append(wxT(".exe"));
  } while(0);
  #endif
  if(wxIsAbsolutePath(argv0Str)) {
    #if defined(LOGGING)
    LOGIT(_T("FindAppPath: AbsolutePath[%s]"), wxPathOnly(argv0Str).GetData());
    #endif
    return wxPathOnly(argv0Str);
  } else {
    wxString currentDir(cwd);
    if(currentDir.Last() != wxFILE_SEP_PATH)
      currentDir += wxFILE_SEP_PATH;
    str = currentDir + argv0Str;
    if(wxFileExists(str)) {
      #if defined(LOGGING)
      LOGIT(_T("FindAppPath: RelativePath[%s]"), wxPathOnly(str).GetData());
      #endif
      return wxPathOnly(str);
    }
  }
  wxPathList pathList;
  pathList.AddEnvList(wxT("PATH"));
  str = pathList.FindAbsoluteValidPath(argv0Str);
  if(!str.IsEmpty()) {
    #if defined(LOGGING)
    LOGIT(_T("FindAppPath: SearchPath[%s]"), wxPathOnly(str).GetData());
    #endif
    return wxPathOnly(str);
  }
  #if defined(LOGGING)
  LOGIT(_T("FindAppPath: Failed, returning cwd"));
  #endif
  return wxEmptyString;
}

void CodeSnippetsAppFrame::OnClose(wxCloseEvent &event) {
  if(m_bOnActivateBusy)
    return;
  if(GetConfig()->GetDragScrollPlugin()) {
    CodeBlocksEvent cbEvent;
    GetConfig()->GetDragScrollPlugin()->OnStartShutdown(cbEvent);
    GetConfig()->GetDragScrollPlugin()->OnRelease(true);
  }
  if(GetSnippetsWindow())
    if(GetSnippetsWindow()->GetFileChanged())
      GetSnippetsWindow()->GetSnippetsTreeCtrl()->SaveItemsToFile(GetConfig()->SettingsSnippetsXmlPath);
  GetConfig()->GetSnippetsWindow()->OnClose(event);
  GetConfig()->m_appIsShutdown = true;
  RemoveKeepAliveFile();
  TerminateRecentFilesHistory();
  if(0 == GetConfig()->GetKeepAlivePid())
    if(Manager::Get()) {
      if(wxFileExists(m_ConfigFolder + _T("/default.conf.backup")))
        wxRemoveFile(m_ConfigFolder + _T("/default.conf.backup")) ;
      if(wxFileExists(m_ConfigFolder + _T("/default.conf.cbTemp")))
        wxRemoveFile(m_ConfigFolder + _T("/default.conf.cbTemp")) ;
    }
  Destroy();
}

void CodeSnippetsAppFrame::OnQuit(wxCommandEvent &event) {
  if(m_bOnActivateBusy)
    return;
  wxCloseEvent evtClose;
  OnClose(evtClose);
}

void CodeSnippetsAppFrame::OnAbout(wxCommandEvent &event) {
  GetSnippetsWindow()->ShowSnippetsAbout(buildInfo);
}

void CodeSnippetsAppFrame::OnSettings(wxCommandEvent& event) {
  SetActiveMenuId(event.GetId());
  GetSnippetsWindow()->OnMnuSettings(event);
}

void CodeSnippetsAppFrame::OnFileLoad(wxCommandEvent& event) {
  SetActiveMenuId(event.GetId());
  if(GetFileChanged()) {
    int answer = GenericMessageBox(wxT("Save Snippets file?\n\n") + GetConfig()->SettingsSnippetsXmlPath,
                                   wxT("Open"), wxYES_NO);
    if(answer == wxYES)
      OnFileSave(event);
  }
  GetConfig()->pSnippetsWindow->OnMnuLoadSnippetsFromFile(event);
  AddToRecentFilesHistory(GetConfig()->SettingsSnippetsXmlPath);
  return;
}

void CodeSnippetsAppFrame::OnFileSave(wxCommandEvent& event) {
  SetActiveMenuId(event.GetId());
  #ifdef LOGGING
  LOGIT(_T("Saving XML file[%s]"), GetConfig()->SettingsSnippetsXmlPath.GetData());
  #endif
  GetSnippetsWindow()->OnMnuSaveSnippets(event);
}

void CodeSnippetsAppFrame::OnFileSaveAs(wxCommandEvent& event) {
  SetActiveMenuId(event.GetId());
  GetConfig()->GetSnippetsWindow()->OnMnuSaveSnippetsAs(event);
  return;
}

void CodeSnippetsAppFrame::OnFileBackup(wxCommandEvent& event) {
  SetActiveMenuId(event.GetId());
  GetConfig()->GetSnippetsWindow()->OnMnuFileBackup(event);
  event.Skip();
  return;
}

void CodeSnippetsAppFrame::OnActivate(wxActivateEvent& event) {
  if(m_bOnActivateBusy) {
    event.Skip();
    return;
  }
  ++m_bOnActivateBusy;
  #if defined(LOGGING)
  #endif
  do {
    if(not event.GetActive())
      break;
    if(not GetConfig()->GetSnippetsWindow())
      break;
    if(not GetConfig()->GetSnippetsTreeCtrl())
      break;
    CodeSnippetsWindow* p = GetConfig()->GetSnippetsWindow();
    if(not p)
      break;
    p->CheckForExternallyModifiedFiles();
  } while(0);
  m_bOnActivateBusy = 0;
  event.Skip();
  return;
}

void CodeSnippetsAppFrame::OnTimerAlarm(wxTimerEvent& event) {
  if(not ::wxFileExists(m_KeepAliveFileName)) {
    RemoveKeepAliveFile();
    wxCloseEvent evtClose(wxEVT_CLOSE_WINDOW, GetId());
    evtClose.SetEventObject(this);
    this->AddPendingEvent(evtClose);
    event.Skip();
    return;
  }
  if(GetConfig()->GetKeepAlivePid()  && (not wxProcess::Exists(GetConfig()->GetKeepAlivePid()))) {
    RemoveKeepAliveFile();
    wxCloseEvent evtClose(wxEVT_CLOSE_WINDOW, GetId());
    evtClose.SetEventObject(this);
    this->AddPendingEvent(evtClose);
    event.Skip();
    return;
  }
  StartKeepAliveTimer(1);
}

void CodeSnippetsAppFrame::OnIdle(wxIdleEvent& event) {
  if(GetConfig()->m_appIsShutdown) {
    event.Skip();
    return;
  }
  wxStatusBar* sb = GetStatusBar();
  if(not sb)
  {event.Skip(); return;}
  if(GetConfig()->m_appIsShutdown)
  { event.Skip(); return; }
  if(sb->GetStatusText() == wxEmptyString)
    sb->SetStatusText(versionStr);
  if(GetConfig()->m_bWindowStateChanged) {
    if(m_bOnActivateBusy)
    {event.Skip(); return;}
    wxCloseEvent evtClose(wxEVT_CLOSE_WINDOW, GetId());
    evtClose.SetEventObject(this);
    this->AddPendingEvent(evtClose);
    GetConfig()->m_bWindowStateChanged = false;
  }
  CodeSnippetsTreeCtrl* pTree = GetConfig()->GetSnippetsTreeCtrl();
  if(pTree)
    pTree->OnIdle();
  event.Skip();
  return;
}

void CodeSnippetsAppFrame::OnEventTest(wxCommandEvent &event) {
  #if defined(LOGGING)
  LOGIT(_T("CodeSnippetsAppFrame::OnEventTest()"));
  #endif
  sDragScrollEvent dsEvt(wxEVT_S_DRAGSCROLL_EVENT, idDragScrollRescan);
  dsEvt.SetEventObject(GetConfig()->GetSnippetsTreeCtrl());
  dsEvt.SetString(GetConfig()->GetSnippetsTreeCtrl()->GetName());
  GetConfig()->GetDragScrollEvtHandler()->AddPendingEvent(dsEvt);
}

bool CodeSnippetsAppFrame::RemoveKeepAliveFile() {
  bool result = ::wxRemoveFile(m_KeepAliveFileName);
  return result;
}

void CodeSnippetsAppFrame::InitializeRecentFilesHistory() {
  TerminateRecentFilesHistory();
  wxMenuBar* mbar = GetMenuBar();
  if(!mbar)
    return;
  int pos = mbar->FindMenu(_("&File"));
  if(pos != wxNOT_FOUND) {
    m_pFilesHistory = new wxFileHistory(9, wxID_FILE1);
    wxMenu* menu = mbar->GetMenu(pos);
    if(!menu)
      return;
    wxMenu* recentFiles = 0;
    wxMenuItem* clear = menu->FindItem(idFileOpenRecentFileClearHistory, &recentFiles);
    if(recentFiles) {
      recentFiles->Remove(clear);
      wxFileConfig cfgFile(wxEmptyString,
                           wxEmptyString,
                           GetConfig()->SettingsSnippetsCfgPath,
                           wxEmptyString,
                           wxCONFIG_USE_LOCAL_FILE);
      m_pFilesHistory->Load(cfgFile);
      wxArrayString files;
      for(int i = 0; i < (int)m_pFilesHistory->GetCount(); ++i)
        files.Add(m_pFilesHistory->GetHistoryFile(i)) ;
      for(int i = (int)files.GetCount() - 1; i >= 0; --i) {
        if(wxFileExists(files[i]))
          m_pFilesHistory->AddFileToHistory(files[i]);
      }
      m_pFilesHistory->UseMenu(recentFiles);
      m_pFilesHistory->AddFilesToMenu(recentFiles);
      if(recentFiles->GetMenuItemCount())
        recentFiles->AppendSeparator();
      recentFiles->Append(clear);
    }
  }
}

void CodeSnippetsAppFrame::AddToRecentFilesHistory(const wxString& FileName) {
  wxString filename = FileName;
  #ifdef __WXMSW__
  wxString low = filename.Lower();
  for(size_t i = 0; i < m_pFilesHistory->GetCount(); ++i) {
    if(low == m_pFilesHistory->GetHistoryFile(i).Lower()) {
      filename = m_pFilesHistory->GetHistoryFile(i);
      break;
    }
  }
  #endif
  m_pFilesHistory->AddFileToHistory(filename);
  wxMenuBar* mbar = GetMenuBar();
  if(!mbar)
    return;
  int pos = mbar->FindMenu(_("&File"));
  if(pos == wxNOT_FOUND)
    return;
  wxMenu* menu = mbar->GetMenu(pos);
  if(!menu)
    return;
  wxMenu* recentFiles = 0;
  wxMenuItem* clear = menu->FindItem(idFileOpenRecentFileClearHistory, &recentFiles);
  if(clear && recentFiles) {
    recentFiles->Remove(clear);
    m_pFilesHistory->RemoveMenu(recentFiles);
    while(recentFiles->GetMenuItemCount())
      recentFiles->Delete(recentFiles->GetMenuItems()[0]);
    m_pFilesHistory->UseMenu(recentFiles);
    m_pFilesHistory->AddFilesToMenu(recentFiles);
    if(recentFiles->GetMenuItemCount())
      recentFiles->AppendSeparator();
    recentFiles->Append(clear);
  }
}

void CodeSnippetsAppFrame::TerminateRecentFilesHistory() {
  if(m_pFilesHistory) {
    wxArrayString files;
    for(unsigned int i = 0; i < m_pFilesHistory->GetCount(); ++i)
      files.Add(m_pFilesHistory->GetHistoryFile(i));
    wxFileConfig cfgFile(wxEmptyString,
                         wxEmptyString,
                         GetConfig()->SettingsSnippetsCfgPath,
                         wxEmptyString,
                         wxCONFIG_USE_LOCAL_FILE);
    m_pFilesHistory->Save(cfgFile);
    cfgFile.Flush();
    wxMenuBar* mbar = GetMenuBar();
    if(mbar) {
      int pos = mbar->FindMenu(_("&File"));
      if(pos != wxNOT_FOUND) {
        wxMenu* menu = mbar->GetMenu(pos);
        if(menu) {
          wxMenu* recentFiles = 0;
          menu->FindItem(idFileOpenRecentFileClearHistory, &recentFiles);
          if(recentFiles)
            m_pFilesHistory->RemoveMenu(recentFiles);
        }
      }
    }
    delete m_pFilesHistory;
    m_pFilesHistory = 0;
  }
}

void CodeSnippetsAppFrame::OnRecentFileReopen(wxCommandEvent& event) {
  size_t id = event.GetId() - wxID_FILE1;
  wxString fname = m_pFilesHistory->GetHistoryFile(id);
  if(GetFileChanged())
    OnFileSave(event);
  if(::wxFileExists(fname)) {
    GetConfig()->SettingsSnippetsXmlPath = fname;
    GetSnippetsWindow()->GetSnippetsTreeCtrl()->LoadItemsFromFile(fname, false);
  } else
    AskToRemoveFileFromHistory(m_pFilesHistory, id);
}

void CodeSnippetsAppFrame::OnRecentFileClearHistory(wxCommandEvent& event) {
  while(m_pFilesHistory->GetCount())
    m_pFilesHistory->RemoveFileFromHistory(0);
}

void CodeSnippetsAppFrame::AskToRemoveFileFromHistory(wxFileHistory* hist, int id) {
  if(cbMessageBox(_("Can't open file.\nDo you want to remove it from the recent files list?"),
                  _("Question"),
                  wxYES_NO | wxICON_QUESTION) == wxID_YES)
    hist->RemoveFileFromHistory(id);
}
bool CodeSnippetsAppFrame::InitializeSDK() {
  wxFileSystem::AddHandler(new wxZipFSHandler);
  wxFileSystem::AddHandler(new wxMemoryFSHandler);
  wxInitAllImageHandlers();
  wxXmlResource::Get()->InitAllHandlers();
  wxXmlResource::Get()->InsertHandler(new wxScrollingDialogXmlHandler);
  LoadConfig();
  ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("app"));
  wxString userPgmData      = cfg->GetFolder(sdDataUser);
  wxString homeFolder       = cfg->GetHomeFolder();
  wxString pluginsFolder    = cfg->GetPluginsFolder(true);
  wxString scriptsFolder    = cfg->GetScriptsFolder(true);
  wxString dataFolderGlobal = cfg->GetDataFolder(true);
  wxString dataFolderUser   = cfg->GetDataFolder(false);
  wxString executableFolder = cfg->GetExecutableFolder();
  wxString tempFolder       = cfg->GetTempFolder();
  Manager::Get(this);
  if(not wxDirExists(dataFolderUser + _T("/lexers")))
    wxMkdir(dataFolderUser + _T("/lexers"));
  m_bInitXRC_Result = InitXRCStuff();
  return m_bInitXRC_Result;
}

bool CodeSnippetsAppFrame::LoadConfig() {
  if(ParseCmdLine(0L) == -1)
    return false;
  ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("app"));
  wxString data(_T(APP_PREFIX));
  if(platform::windows)
    data.assign(GetAppPath());
  else if(platform::macosx) {
    data.assign(GetResourcesDir());
    if(!data.Contains(wxString(_T("/Resources"))))
      data = GetAppPath() + _T("/..");
  }
  if(data.IsEmpty()) {
    data.assign(GetAppPath());
    data.Replace(_T("/bin"), _T(""));
  }
  if(!m_Prefix.IsEmpty())
    data = m_Prefix;
  else {
    wxString env;
    wxGetEnv(_T("CODEBLOCKS_DATA_DIR"), &env);
    if(!env.IsEmpty())
      data = env;
  }
  data.append(_T("/share/codeblocks"));
  cfg->Write(_T("data_path"), data);
  return true;
}

wxString CodeSnippetsAppFrame::GetAppPath() {
  wxString base;
  #ifdef __WXMSW__
  wxChar name[MAX_PATH] = {0};
  GetModuleFileName(0L, name, MAX_PATH);
  wxFileName fname(name);
  base = fname.GetPath(wxPATH_GET_VOLUME);
  #else
  if(!m_Prefix.IsEmpty())
    return m_Prefix;
  #ifdef SELFPATH
  base = wxString(SELFPATH, wxConvUTF8);
  base = wxFileName(base).GetPath();
  #endif
  #if defined(sun) || defined(__sun)
  base = wxString(getexecname(), wxConvCurrent);
  base = wxFileName(base).GetPath();
  #endif
  #if defined(__APPLE__) && defined(__MACH__)
  char path[MAXPATHLEN + 1];
  uint32_t path_len = MAXPATHLEN;
  _NSGetExecutablePath(path, &path_len);
  base = wxString(path, wxConvUTF8);
  base = wxFileName(base).GetPath();
  #endif
  if(base.IsEmpty())
    base = FindAppPath(wxTheApp->argv[0], ::wxGetCwd(), wxEmptyString);;
  #endif
  return base;
}

bool CodeSnippetsAppFrame::InitXRCStuff() {
  if(!Manager::LoadResource(_T("resources.zip"))) {
    ComplainBadInstall();
    return false;
  }
  return true;
}

void CodeSnippetsAppFrame::ComplainBadInstall() {
  wxString msg;
  msg.Printf(_T("Cannot find resources...\n"
                "%s was configured to be installed in '%s'.\n"
                "Please use the command-line switch '--prefix' or "
                "set the CODEBLOCKS_DATA_DIR environment variable "
                "to point where %s is installed,\n"
                "or try re-installing the application..."),
             _T("CodeSnippetsApp"),
             ConfigManager::ReadDataPath().c_str(),
             wxTheApp->GetAppName().c_str());
  cbMessageBox(msg);
}

#if wxUSE_CMDLINE_PARSER

#if wxCHECK_VERSION(3, 0, 0)
#define CMD_ENTRY(X) X
#else
#define CMD_ENTRY(X) _T(X)
#endif

const wxCmdLineEntryDesc cmdLineDesc[] = {
  { wxCMD_LINE_SWITCH, CMD_ENTRY("h"), CMD_ENTRY("help"), CMD_ENTRY("show this help message"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
  { wxCMD_LINE_OPTION, CMD_ENTRY(""), CMD_ENTRY("prefix"),  CMD_ENTRY("the shared data dir prefix"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_NEEDS_SEPARATOR },
  { wxCMD_LINE_OPTION, CMD_ENTRY("p"), CMD_ENTRY("personality"),  CMD_ENTRY("the personality to use: \"ask\" or <personality-name>"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_NEEDS_SEPARATOR },
  { wxCMD_LINE_OPTION, CMD_ENTRY(""), CMD_ENTRY("profile"),  CMD_ENTRY("synonym to personality"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_NEEDS_SEPARATOR },
  { wxCMD_LINE_OPTION, CMD_ENTRY(""), CMD_ENTRY("KeepAlivePid"),  CMD_ENTRY("launchers pid"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_NEEDS_SEPARATOR },
  { wxCMD_LINE_OPTION, CMD_ENTRY(""), CMD_ENTRY("AppParent"),  CMD_ENTRY("parent app name"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_NEEDS_SEPARATOR },
  { wxCMD_LINE_NONE }
};
#endif

int CodeSnippetsAppFrame::ParseCmdLine(wxFrame* handlerFrame) {
  bool filesInCmdLine = false;
  #if wxUSE_CMDLINE_PARSER
  wxCmdLineParser& parser = *Manager::GetCmdLineParser();
  parser.SetDesc(cmdLineDesc);
  parser.SetCmdLine(wxTheApp->argc, wxTheApp->argv);
  switch(parser.Parse(false)) {
    case -1:
      parser.Usage();
      return -1;
    case 0: {
      {
        wxString val;
        parser.Found(_T("prefix"), &m_Prefix);
        if(parser.Found(_T("personality"), &val) ||
            parser.Found(_T("profile"), &val)) {
        }
      }
    }
    break;
    default:
      return 1;
  }
  #endif
  return filesInCmdLine ? 1 : 0;
}

void CodeSnippetsAppFrame::ImportCBResources() {
  wxString appConfigFolder =  Normalize(m_ConfigFolder) ;
  wxString appExeFolder = Normalize(FindAppPath(wxTheApp->argv[0], ::wxGetCwd(), wxEmptyString));
  wxString cbExeFolder = Normalize(GetCBExeFolder());
  wxString cbConfigFolder = Normalize(wxStandardPaths::Get().GetUserDataDir());
  wxString appParent = GetConfig()->GetAppParent();
  if(appParent.empty())
    appParent = _T("codeblocks");
  wxString prefixPath;
  #if defined(__WXMSW__)
  if(cbConfigFolder.EndsWith(_T("codesnippets"), &prefixPath))
    cbConfigFolder = prefixPath.Append(appParent);
  #else
  if(cbConfigFolder.EndsWith(_T(".codesnippets"), &prefixPath))
    cbConfigFolder = prefixPath.Append(wxT(".") + appParent);
  #endif
  wxString fileToCopy = cbConfigFolder + _T("/default.conf");
  if(wxFileExists(fileToCopy)) {
    if(appConfigFolder == appExeFolder)
      if(not wxFileExists(appExeFolder + _T("/default.conf"))) {
        #if defined(LOGGING)
        bool copied =
        #endif
          wxCopyFile(fileToCopy, appExeFolder + _T("/default.conf"));
        #if defined(LOGGING)
        LOGIT(_T("Copy [%s][%s][%s]"), fileToCopy.c_str(), cbConfigFolder.c_str(), copied ? _T("OK") : _T("FAILED"));
        #endif
      }
  }
  if(not wxDirExists(appExeFolder + _T("/share/codeblocks/"))) {
    FileImport(cbExeFolder + _T("/share/codeblocks/images/"), appExeFolder + _T("/share/codeblocks/images/"));
    FileImport(cbExeFolder + _T("/share/codeblocks/lexers/"), appExeFolder + _T("/share/codeblocks/lexers/"));
    FileImport(cbExeFolder + _T("/share/codeblocks/manager_resources.zip"), appExeFolder + _T("/share/codeblocks/"));
    FileImport(cbExeFolder + _T("/share/codeblocks/resources.zip"), appExeFolder + _T("/share/codeblocks/"));
    FileImport(cbExeFolder + _T("/share/codeblocks/xpmanifest.zip"), appExeFolder + _T("/share/codeblocks/"));
  }
}
wxString CodeSnippetsAppFrame::GetCBExeFolder() {
  wxString cbExeFolder = GetAppPath();
  #if defined(__WXMSW__)
  if(m_Prefix.IsEmpty())
    do {
      wxChar dllPath[1024] = {0};
      HMODULE dllHandle = LoadLibrary(_T("codeblocks.dll"));
      if(not dllHandle)
        break;
      DWORD pathLen = GetModuleFileName(dllHandle, dllPath, sizeof(dllPath));
      if(not pathLen)
        break;
      cbExeFolder.assign(::wxPathOnly(dllPath));
      #if defined(LOGGING)
      LOGIT(_T("CodeBlocks.dll Path[%s]"), cbExeFolder.c_str());
      #endif
    } while(false);
  #endif
  return cbExeFolder;
}

bool CodeSnippetsAppFrame::FileImport(const wxString& source, const wxString& dest) {
  wxString msg = wxEmptyString;
  #if defined(LOGGING)
  #endif
  if(::wxDirExists(source)) {
    #if defined(LOGGING)
    #endif
    wxDir dir(source);
    if(dir.IsOpened()) {
      FileImportTraverser dirTraverser(source, dest);
      dir.Traverse(dirTraverser);
    }
  } else {
    wxString srcNative(source);
    #if defined(LOGGING)
    #endif
    wxString destfile = dest;
    if(::wxDirExists(destfile))
      destfile += wxFileName(srcNative).GetFullName();
    ::wxCopyFile(srcNative, destfile);
  }
  return true;
}

wxString CodeSnippetsAppFrame::Normalize(const wxString& filenamein) {
  wxFileName filename(filenamein);
  filename.Normalize();
  return filename.GetFullPath();
}
